import time
import threading
import socket
import paramiko
from django.core.management.base import BaseCommand
from django.utils import timezone
from cmdb.models import Host
import logging

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = '主机心跳检测服务'

    def add_arguments(self, parser):
        parser.add_argument(
            '--interval',
            type=int,
            default=60,
            help='检测间隔（秒），默认60秒'
        )
        parser.add_argument(
            '--timeout',
            type=int,
            default=10,
            help='连接超时时间（秒），默认10秒'
        )

    def handle(self, *args, **options):
        interval = options['interval']
        timeout = options['timeout']
        
        self.stdout.write(
            self.style.SUCCESS(f'启动主机心跳检测服务，检测间隔: {interval}秒，超时时间: {timeout}秒')
        )
        
        try:
            while True:
                self.check_all_hosts(timeout)
                time.sleep(interval)
        except KeyboardInterrupt:
            self.stdout.write(self.style.WARNING('心跳检测服务已停止'))

    def check_all_hosts(self, timeout):
        """检测所有主机的连通性"""
        hosts = Host.objects.all()
        self.stdout.write(f'开始检测 {hosts.count()} 台主机...')
        
        # 使用线程池并发检测
        threads = []
        for host in hosts:
            thread = threading.Thread(target=self.check_host, args=(host, timeout))
            thread.start()
            threads.append(thread)
        
        # 等待所有线程完成
        for thread in threads:
            thread.join()
        
        self.stdout.write('本轮检测完成')

    def check_host(self, host, timeout):
        """检测单个主机的连通性"""
        try:
            # 更新状态为检测中
            host.status = 'checking'
            host.save(update_fields=['status'])
            
            # 首先进行ping检测
            if self.ping_check(host.ip_address, timeout):
                # ping通过，进行SSH连接检测
                if self.ssh_check(host, timeout):
                    status = 'online'
                    message = f'主机 {host.hostname} 在线'
                else:
                    status = 'error'
                    message = f'主机 {host.hostname} ping通但SSH连接失败'
            else:
                status = 'offline'
                message = f'主机 {host.hostname} 离线'
            
            # 更新主机状态
            host.status = status
            host.last_check_time = timezone.now()
            host.save(update_fields=['status', 'last_check_time'])
            
            self.stdout.write(message)
            
        except Exception as e:
            # 检测异常
            host.status = 'error'
            host.last_check_time = timezone.now()
            host.save(update_fields=['status', 'last_check_time'])
            
            error_msg = f'检测主机 {host.hostname} 时发生异常: {str(e)}'
            self.stdout.write(self.style.ERROR(error_msg))
            logger.error(error_msg)

    def ping_check(self, ip_address, timeout):
        """ping检测"""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(timeout)
            result = sock.connect_ex((ip_address, 22))  # 检测SSH端口
            sock.close()
            return result == 0
        except Exception:
            return False

    def ssh_check(self, host, timeout):
        """SSH连接检测"""
        try:
            ssh_client = paramiko.SSHClient()
            ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            ssh_client.connect(
                hostname=host.ip_address,
                port=host.ssh_port or 22,
                username=host.ssh_username or 'root',
                password=host.ssh_password,
                timeout=timeout
            )
            
            ssh_client.close()
            return True
            
        except Exception:
            return False
